package jobscheduling.algorithms.pso;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import jobscheduling.algorithms.ResultListener;

public class Swarm 
{
	private List<Particle> particleList = new ArrayList<Particle>();
	private Evaluator ev;
	private double c1;
	private double c2;
	private double w;
	private int np;
	private double vmax;
	private ResultListener resultListener = null;
	
	public void setResultListener(ResultListener resl)
	{
		resultListener = resl;
	}
	
	
	private int[][] bestSolution = null;
	
	public Swarm(int n, int np, Evaluator ev)	
	/*liczba zadań, liczba cząsteczek, obiekt obliczajacy czas rozwiazania*/
	{
		this.ev = ev;	/*inicjalizuje parametry*/
		this.w = 1.0;
		this.c1 = 1.5;
		this.c2 = 1.5;
		this.np = np;
		this.vmax = 20.0;
		
		List<Integer> l = new ArrayList<Integer>(n + 1);	/*generuje początkowe, losowe cząstki*/
		for(int i=0; i<n; i++)
			l.add(i);
		for(int i = 0; i<np; i++)
		{
			Collections.shuffle(l);
			particleList.add(new Particle(l, n));
		}	
	}
	
	public Swarm(int n, int np, Evaluator ev, double w, double c1, double c2, double vmax)	
	/*liczba zadań, liczba cząsteczek, obiekt obliczajacy czas rozwiazania, waga bezwładości, współczynnik poznawczy, współczynnik społeczny, górne ograniczenie prrędkości*/
	{
		this.ev = ev;	/*inicjalizuje parametry*/
		this.w = w;
		this.c1 = c1;
		this.c2 = c2;
		this.np = np;
		this.vmax = vmax;
		
		List<Integer> l = new ArrayList<Integer>(n + 1);	/*generuje początkowe, losowe cząstki*/
		for(int i=0; i<n; i++)
			l.add(i);
		for(int i = 0; i<np; i++)
		{
			Collections.shuffle(l);
			particleList.add(new Particle(l, n));
		}	
	}
	
	public int[] seekSolution(int iterations)
	{
		int g=0;	//g to numer cząstki która posiada najlepsze rozwiązanie
		int j;
		/*każda cząstka przechowuje swoje nakjlepsze dotychczasowe rozwiazanie!*/
		for(int i=0; i<np; i++)
			particleList.get(i).setCurrentSolutionAsBest();
		/*rój przechowuje najlepsze globalne rozwiązanie (gbest)*/
		bestSolution = particleList.get(0).copyBestSolution();
		
		Particle currentParticle = null;
		for(int i=0; i<iterations; i++)
		{
			//Printer.print(bestSolution);
			for(j=0; j<np; j++)	//sprawdź czy nowe rozwiazanie jest lepsze
			{
				currentParticle = particleList.get(j);
				if(ev.compare(currentParticle.jobPositions, currentParticle.bestSolution))
					currentParticle.setCurrentSolutionAsBest();
			}
			
			
			g=0;	//znajdż najlepsze globalne rozwiąznie
			for(j=0; j<np; j++)
			{
				if(ev.compare(particleList.get(j), particleList.get(g)))
					g=j;
				//if (resultListener != null)
					//resultListener.newResult(ev.convertIntoSolution(particleList.get(j)), ev.eval(particleList.get(j)));
			}
			if(ev.compare(particleList.get(g).jobPositions, bestSolution))	//porównaj najlepsze obecne rozwiązanie z poprzednim najleszym
				bestSolution = particleList.get(g).copyBestSolution();
		
			
			for(j=0; j< np; j++)	//aktualizuj predkości
			{
				particleList.get(j).updateVelocity(w, c1, c2, vmax, bestSolution);
			}
			
			for(j=0; j<np; j++)		//konstruuj nowe możliwe rozwiązania
			{
				particleList.get(j).constructNewSolution(bestSolution, ev);
				//resultListener.newResult(ev.convertIntoSolution(particleList.get(j).jobPositions), ev.eval(particleList.get(j).jobPositions));
			}
			//System.out.println();
			
			if (resultListener != null)
				resultListener.newResult(ev.convertIntoSolution(bestSolution), ev.eval(bestSolution));
				//resultListener.newResult(ev.convertIntoSolution(particleList.get(0).bestSolution), ev.eval(particleList.get(0).bestSolution));
			//System.out.println();
		}
		
		return ev.convertIntoSolution(bestSolution);
	}

	public void setCognitionLearmningFactor(double c1) {
		this.c1 = c1;
	}

	public void setSocialLearningFactor(double c2) {
		this.c2 = c2;
	}

	public void setInertiaWeight(double w) {
		this.w = w;
	}

	public void setMaxVelocity(double vmax) {
		this.vmax = vmax;
	}
	
	
}
